﻿
namespace SistemaLogistica.DataAccess
{
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Data.Common;
    using SistemaLogistica.Business.Entities;
    using SistemaLogistica.Business.Entities.Types;

    public class PedidoData : BaseDataAccess
    {
        private PedidoData() { }

        private readonly static PedidoData instancia = new PedidoData();

        public static PedidoData Instancia
        {
            get { return instancia; }
        }

        public List<Pedido> ListarPorTipo(PedidoType tipo)
        {
            List<Pedido> pedidos = new List<Pedido>();

            DbCommand command = db.GetStoredProcCommand("GetPedidoByTipoPedido");
            db.AddInParameter(command, "tipoPedido", DbType.Int32, (int)tipo);

            using (IDataReader dr = db.ExecuteReader(command))
            {
                while (dr.Read())
                {
                    pedidos.Add(new Pedido
                    {
                        IdPedido = dr.GetInt32(dr.GetOrdinal("IdPedido")),
                        Fecha = dr.GetDateTime(dr.GetOrdinal("Fecha")),
                        TipoPedido = dr.GetInt32(dr.GetOrdinal("TipoPedido")),
                        Estado = dr.GetBoolean(dr.GetOrdinal("Estado")),
                        Descripcion = dr.GetString(dr.GetOrdinal("Descripcion")),
                        Area = AreaData.Instancia.ObtenerPorID(dr.GetInt32(dr.GetOrdinal("IdArea"))),
                        Empleados = EmpleadoData.Instancia.ObtenerPorID(dr.GetInt16(dr.GetOrdinal("IdEmpleado")))
                    });
                }
            }
            return pedidos;
        }

        public List<Pedido> Buscar(DateTime desde, DateTime hasta, PedidoType tipo)
        {
            List<Pedido> pedidos = new List<Pedido>();

            DbCommand command = db.GetStoredProcCommand("SearchPedidos");
            db.AddInParameter(command, "tipoPedido", DbType.Int32, (int)tipo);
            db.AddInParameter(command, "desde", DbType.DateTime, desde);
            db.AddInParameter(command, "hasta", DbType.DateTime, hasta);

            using (IDataReader dr = db.ExecuteReader(command))
            {
                while (dr.Read())
                {
                    pedidos.Add(new Pedido
                    {
                        IdPedido = dr.GetInt32(dr.GetOrdinal("IdPedido")),
                        Fecha = dr.GetDateTime(dr.GetOrdinal("Fecha")),
                        TipoPedido = dr.GetInt32(dr.GetOrdinal("TipoPedido")),
                        Estado = dr.GetBoolean(dr.GetOrdinal("Estado")),
                        Descripcion = dr.GetString(dr.GetOrdinal("Descripcion")),
                        Area = AreaData.Instancia.ObtenerPorID(dr.GetInt32(dr.GetOrdinal("IdArea"))),
                        Empleados = EmpleadoData.Instancia.ObtenerPorID(dr.GetInt16(dr.GetOrdinal("IdEmpleado")))
                    });
                }
            }
            return pedidos;
        }

        public Pedido ObtenerPorID(int idPedido)
        {
            Pedido pedido = null;

            DbCommand command = db.GetStoredProcCommand("GetPedidoByIdPedido");
            db.AddInParameter(command, "idPedido", DbType.Int32, idPedido);

            using (IDataReader dr = db.ExecuteReader(command))
            {
                if (dr.Read())
                {
                    pedido = new Pedido
                    {
                        IdPedido = dr.GetInt32(dr.GetOrdinal("IdPedido")),
                        Fecha = dr.GetDateTime(dr.GetOrdinal("Fecha")),
                        TipoPedido = dr.GetInt32(dr.GetOrdinal("TipoPedido")),
                        Estado = dr.GetBoolean(dr.GetOrdinal("Estado")),
                        Descripcion = dr.GetString(dr.GetOrdinal("Descripcion")),
                        Area = AreaData.Instancia.ObtenerPorID(dr.GetInt32(dr.GetOrdinal("IdArea"))),
                        Empleados = EmpleadoData.Instancia.ObtenerPorID(dr.GetInt16(dr.GetOrdinal("IdEmpleado"))),
                        Detalle = DetallePedidoData.Instancia.ListarPorPedido(idPedido)
                    };
                }
            }
            return pedido;
        }

        public void Registrar(Pedido pedido)
        {
            using (DbConnection conection = db.CreateConnection())
            {
                conection.Open();
                using (DbTransaction transaction = conection.BeginTransaction())
                {
                    try
                    {
                        DbCommand cmdPedido = db.GetStoredProcCommand("InsertPedido");
                        db.AddInParameter(cmdPedido, "descripcion", DbType.String, pedido.Descripcion);
                        db.AddInParameter(cmdPedido, "estado", DbType.Boolean, pedido.Estado);
                        db.AddInParameter(cmdPedido, "fecha", DbType.DateTime, pedido.Fecha);
                        db.AddInParameter(cmdPedido, "idArea", DbType.Int32, pedido.Area.IdArea);
                        db.AddInParameter(cmdPedido, "idEmpleado", DbType.Int16, pedido.Empleados.IdEmpleado);
                        db.AddOutParameter(cmdPedido, "idPedido", DbType.Int32, 11);
                        db.AddInParameter(cmdPedido, "tipoPedido", DbType.Int32, pedido.TipoPedido);

                        int result = db.ExecuteNonQuery(cmdPedido, transaction);
                        if (result == 0) throw new Exception();

                        int idPedido = Convert.ToInt32(db.GetParameterValue(cmdPedido, "idPedido"));

                        DbCommand cmdDetalle = db.GetStoredProcCommand("InsertDetallePedido");
                        db.AddInParameter(cmdDetalle, "cantidad", DbType.Decimal);
                        db.AddInParameter(cmdDetalle, "descripcion", DbType.String);
                        db.AddInParameter(cmdDetalle, "estado", DbType.Boolean);
                        db.AddInParameter(cmdDetalle, "idBien", DbType.Int32);
                        db.AddInParameter(cmdDetalle, "idPedido", DbType.Int32);

                        foreach (DetallePedido d in pedido.Detalle)
                        {
                            db.SetParameterValue(cmdDetalle, "cantidad", d.Cantidad);
                            db.SetParameterValue(cmdDetalle, "descripcion", d.Descripcion);
                            db.SetParameterValue(cmdDetalle, "estado", d.Estado);
                            db.SetParameterValue(cmdDetalle, "idBien", d.IdBien);
                            db.SetParameterValue(cmdDetalle, "idPedido", idPedido);
                            db.ExecuteNonQuery(cmdDetalle, transaction);
                        }

                        transaction.Commit();
                    }
                    catch (Exception ex)
                    {
                        transaction.Rollback();
                        throw ex;
                    }
                }
            }
        }

        public void Modificar(Pedido pedido)
        {
            using (DbConnection conection = db.CreateConnection())
            {
                conection.Open();
                using (DbTransaction transaction = conection.BeginTransaction())
                {
                    try
                    {
                        DbCommand cmdPedido = db.GetStoredProcCommand("UpdatePedido");
                        db.AddInParameter(cmdPedido, "descripcion", DbType.String, pedido.Descripcion);
                        db.AddInParameter(cmdPedido, "estado", DbType.Boolean, pedido.Estado);
                        db.AddInParameter(cmdPedido, "fecha", DbType.DateTime, pedido.Fecha);
                        db.AddInParameter(cmdPedido, "idArea", DbType.Int32, pedido.Area.IdArea);
                        db.AddInParameter(cmdPedido, "idEmpleado", DbType.Int16, pedido.Empleados.IdEmpleado);
                        db.AddInParameter(cmdPedido, "idPedido", DbType.Int32, pedido.IdPedido);
                        db.AddInParameter(cmdPedido, "tipoPedido", DbType.Int32, pedido.TipoPedido);

                        int result = db.ExecuteNonQuery(cmdPedido, transaction);
                        if (result == 0) throw new Exception();

                        DbCommand cmdDeleteDetalle = db.GetStoredProcCommand("DeleteDetallePedidoByPedido");
                        db.AddInParameter(cmdDeleteDetalle, "idPedido", DbType.Int32, pedido.IdPedido);
                        db.ExecuteNonQuery(cmdDeleteDetalle, transaction);

                        DbCommand cmdDetalle = db.GetStoredProcCommand("InsertDetallePedido");
                        db.AddInParameter(cmdDetalle, "cantidad", DbType.Decimal);
                        db.AddInParameter(cmdDetalle, "descripcion", DbType.String);
                        db.AddInParameter(cmdDetalle, "estado", DbType.Boolean);
                        db.AddInParameter(cmdDetalle, "idBien", DbType.Int32);
                        db.AddInParameter(cmdDetalle, "idPedido", DbType.Int32);

                        foreach (DetallePedido d in pedido.Detalle)
                        {
                            db.SetParameterValue(cmdDetalle, "cantidad", d.Cantidad);
                            db.SetParameterValue(cmdDetalle, "descripcion", d.Descripcion);
                            db.SetParameterValue(cmdDetalle, "estado", d.Estado);
                            db.SetParameterValue(cmdDetalle, "idBien", d.IdBien);
                            db.SetParameterValue(cmdDetalle, "idPedido", pedido.IdPedido);
                            db.ExecuteNonQuery(cmdDetalle, transaction);
                        }

                        transaction.Commit();
                    }
                    catch (Exception ex)
                    {
                        transaction.Rollback();
                        throw ex;
                    }
                }
            }
        }

        public void Eliminar(int idPedido)
        {
            DbCommand command = db.GetStoredProcCommand("DeletePedido");
            db.AddInParameter(command, "idPedido", DbType.Int32, idPedido);
            db.ExecuteNonQuery(command);
        }
    }
}
